﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using OverStore.Runtime.PersistenceServiceProvider;
using System.Globalization;

namespace OverStore.Runtime.ObjectRepository.CallbackManager
{
    /// <summary>
    /// Process notification about persistence operation performed on instances of <typeparamref name="TInstance"/> type using user-defined delegates.
    /// </summary>
    /// <typeparam name="TInstance">The type of instance.</typeparam>
    public sealed class DelegateCallbackManager<TInstance> : ICallbackManager<TInstance>
        where TInstance : class
    {
        private readonly IPersistenceServiceProvider _Provider;
        private readonly IEnumerable<Func<TInstance, PersistenceOperation, IPersistenceServiceProvider, bool>> _CallbackDelegates;

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateCallbackManager&lt;TInstance&gt;"/> class.
        /// </summary>
        /// <param name="provider">The provider.</param>
        /// <param name="callbackDelegates">The callback delegates.</param>
        public DelegateCallbackManager(IPersistenceServiceProvider provider,
            IEnumerable<Func<TInstance, PersistenceOperation, IPersistenceServiceProvider, bool>> callbackDelegates)
        {
            if (Object.ReferenceEquals(provider, null))
                throw new ArgumentNullException("provider");
            _Provider = provider;
            _CallbackDelegates = callbackDelegates;
        }

        /// <summary>
        /// Performs operations as response to specified action.
        /// If method returns <c>false</c>, the operation which provides callback must be interrupted.
        /// Some operation can't be interrupted.
        /// </summary>
        /// <param name="instance">The instance been argument of persistence operation.</param>
        /// <param name="operation">The persistence operation performed on instance.</param>
        /// <returns>
        /// 	<c>true</c> to continue persistence operation, <c>false</c> to stop persistence operation.
        /// </returns>
        /// <exception cref="PersistingRuntimeException">Error occured due callback processing.</exception>
        bool ICallbackManager<TInstance>.Callback(TInstance instance, PersistenceOperation operation)
        {
            if (_CallbackDelegates == null)
                return true;
            try
            {
                // If any callback delegate returns false, method returns false.
                var result = true;
                foreach (var subResult in _CallbackDelegates.Select(d => d(instance, operation, _Provider)))
                    result = result && subResult;
                return result;
            }
            catch (PersistingRuntimeException)
            {
                throw;
            }
            catch (Exception ex)
            {
                var message = ex.Message;
                if (String.IsNullOrEmpty(message))
                    message = String.Format("Error occured due callback operation {0} for entity {1}.", operation, typeof(TInstance));
                throw new PersistingRuntimeException(message, ex, true);
            }
        }
    }
}
